/*
 * Copyright 2013 Krzysztof Smigielski
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.nilcaream.dirstore.core.processor;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.nilcaream.dirstore.core.common.ArchiveCreator;
import com.nilcaream.dirstore.core.common.ProgressMeter;
import com.nilcaream.dirstore.core.common.TypeAwareTrimmer;
import com.nilcaream.dirstore.core.common.ZipTool;
import com.nilcaream.dirstore.core.model.Archive;
import com.nilcaream.dirstore.core.model.ArchiveElement;
import com.nilcaream.dirstore.core.model.TrimmedElement;

import javax.inject.Inject;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.ZipOutputStream;

import static com.nilcaream.dirstore.core.common.Utils.toReadableFileSize;

/**
 * TODO
 * <p/>
 * Krzysztof Smigielski 7/7/13 1:03 PM
 */
public class DirectoryTrimmer implements ArchiveCreator {

    @Inject
    private ArchivingVisitorFactory visitorFactory;

    @Inject
    private ZipTool zipTool;

    @Inject
    private TypeAwareTrimmer trimmer;

    @Inject
    private ProgressMeter progressMeter;

    @Override
    public Archive createArchive(Path root) throws IOException {
        Preconditions.checkArgument(root.toFile().isDirectory(), root.toString() + " is not a directory");
        Archive archive = new Archive();
        archive.setElements(Lists.<ArchiveElement>newArrayListWithCapacity(1000));
        Files.walkFileTree(root, visitorFactory.create(archive, root));
        return archive;
    }

    public void createTrimmedZip(Archive archive, OutputStream outputStream) throws IOException {
        TrimmedElement directory = new TrimmedElement();
        directory.setCompressionNeeded(false);
        directory.setData(new byte[]{});
        progressMeter.initialize(archive);
        long totalSize = 0;
        try (ZipOutputStream zipOutputStream = zipTool.createZipOutput(outputStream)) {
            for (ArchiveElement archiveElement : archive.getElements()) {
                if (archiveElement.isDirectory()) {
                    zipTool.add(archiveElement, directory, zipOutputStream);
                } else {
                    try (InputStream inputStream = archiveElement.getUri().toURL().openStream()) {
                        TrimmedElement trimmedElement = trimmer.trim(inputStream, archiveElement.getName());
                        zipTool.add(archiveElement, trimmedElement, zipOutputStream);
                    }
                    totalSize += archiveElement.getOriginalSize();
                }
                progressMeter.increment(archive);
            }
            zipOutputStream.setComment(toReadableFileSize(totalSize));
        }
    }
}
